package com.smh;

import com.smh.interfaces.BlockingQueue;
import org.junit.jupiter.api.Test;

import java.util.Iterator;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author shiminghui
 * @date 2025/2/18 20:01
 * @description: TODO
 */
public class _027_阻塞队列_单锁 {


    @Test
    public void test1() throws InterruptedException {
        BlockingQueue<Integer> blockingQueue = new BlockingQueue<>(10);
        for (int i = 0; i < 10; i++) {
            blockingQueue.offer(i);
        }
        new Thread(() -> {
            try {
                blockingQueue.offer(1, 1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }, "t1").start();
        new Thread(() -> {
            try {
                blockingQueue.poll();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }, "t2").start();

        for (Integer t : blockingQueue) {
            System.out.println(t);
        }
    }


    private static class BlockingQueue<T> implements com.smh.interfaces.BlockingQueue<T>, Iterable<T> {

        private T[] array;
        private int size;
        private int head;
        private int tail;
        private int capacity;
        private ReentrantLock lock = new ReentrantLock(); // 锁对象，可重入锁
        private Condition notFull = lock.newCondition(); // 条件变量对象
        private Condition notEmpty = lock.newCondition();


        public BlockingQueue(int capacity) {
            this.capacity = capacity;
            array = (T[]) new Object[capacity];
        }

        public BlockingQueue() {
            this(10);
        }

        @Override
        public void offer(T value) throws InterruptedException {
            lock.lockInterruptibly();
            try {
                while (isFull()) {
                    notFull.await();
                }
                array[tail++] = value;
                tail = tail % capacity;
                size++;
                notEmpty.signal();
            } finally {
                lock.unlock();
            }
        }

        @Override
        public boolean offer(T value, long timeout) throws InterruptedException {
            lock.lockInterruptibly();
            try {
                long t = TimeUnit.MILLISECONDS.toNanos(timeout);
                while (isFull()) {
                    t = notFull.awaitNanos(t); // 剩余时间,每次不会重置，而是继续减，返回值是剩余时间
                }
                array[tail++] = value;
                tail = tail % capacity;
                size++;
                notEmpty.signal();
                return true;
            } finally {
                lock.unlock();
            }
        }

        @Override
        public T poll() throws InterruptedException {
            lock.lock();
            try {
                while (isEmpty()) {
                    notEmpty.await();
                }
                T t = array[head++];
                array[head - 1] = null; // 避免内存泄漏
                head = head % capacity;
                size--;
                notFull.signal();
                return t;
            } finally {
                lock.unlock();
            }
        }

        public boolean isEmpty() {
            return size == 0;
        }

        public boolean isFull() {
            return size == capacity;
        }

        @Override
        public Iterator<T> iterator() {
            return new Iterator<T>() {
                int index = head;
                int count = size;

                @Override
                public boolean hasNext() {
                    if (count != 0) {
                        return true;
                    }
                    return false;
                }

                @Override
                public T next() {
                    T value = array[index++];
                    index = index % capacity;
                    count--;
                    return value;
                }
            };
        }
    }

}
